package bigoo.peer.message;

import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;

import bigoo.common.communication.AbstractMessage;
import bigoo.common.communication.InvalidMessageException;
import bigoo.common.communication.Message;
import bigoo.common.communication.MessageBuilder;
import bigoo.peer.ride.Ride;

public class PublishRideMessage extends AbstractMessage {

    private static final String RIDE_ID_SEPARATOR = ":";

    public static final String MSG_IDENTIFIER = "PUBLISH_RIDE";
    private Collection<Ride> rides = new LinkedList<Ride>();;
    private String senderIp;
    private int senderPort;

    public PublishRideMessage(String senderID, String senderIp, int senderPort) {
	super(senderID, MSG_IDENTIFIER);
	this.senderPort = senderPort;
	this.senderIp = senderIp;
    }

    public PublishRideMessage(String senderID, String senderIp, int senderPort, Collection<Ride> rides) {
	this(senderID, senderIp, senderPort);
	this.rides = rides;
    }

    public void addRide(String destination, String rideID, String peerID, String peerAddress, int peerPort, int places, Date timestamp, int version) {
	this.rides.add(new Ride(destination, rideID, peerID, peerAddress, peerPort, places, timestamp, version));
    }

    public Collection<Ride> getRides() {
	return this.rides;
    }

    public String getSenderIpAddress() {
	return senderIp;
    }

    public void setSenderIp(String senderIp) {
	this.senderIp = senderIp;
    }

    public int getSenderPort() {
	return senderPort;
    }

    public void setSenderPort(int senderPort) {
	this.senderPort = senderPort;
    }

    @Override
    public String getRawMessage() {
	StringBuilder buf = new StringBuilder();
	buf.append(this.getSenderID() + SEPARATOR + MSG_IDENTIFIER + SEPARATOR + getSenderIpAddress() + SEPARATOR + getSenderPort() + SEPARATOR);
	for (Ride ride : this.rides) {
	    // [riderID.rideID.version,riderTCPAddress,riderTCPport,destination,places,time]
	    buf.append(ride.getPeerID());
	    buf.append(RIDE_ID_SEPARATOR);
	    buf.append(ride.getRideID());
	    buf.append(RIDE_ID_SEPARATOR);
	    buf.append(ride.getVersion());
	    buf.append(PARAM_SEPARATOR);
	    buf.append(ride.getPeerAddress());
	    buf.append(PARAM_SEPARATOR);
	    buf.append(ride.getPeerPort());
	    buf.append(PARAM_SEPARATOR);
	    buf.append(ride.getDestination());
	    buf.append(PARAM_SEPARATOR);
	    buf.append(ride.getPlaces());
	    buf.append(PARAM_SEPARATOR);
	    buf.append(ride.getTimestamp().getTime());
	    buf.append(LIST_SEPARATOR);
	}
	buf.append(END_OF_MESSAGE);
	return buf.toString();
    }

    public static class Builder implements MessageBuilder {

	@Override
	public Message parseMessage(String rawMessage) throws InvalidMessageException {
	    try {
		String senderID = parseSenderID(rawMessage);
		String senderIp = parseSenderIP(rawMessage);
		int senderPort = parseSenderPort(rawMessage);
		PublishRideMessage msg = new PublishRideMessage(senderID, senderIp, senderPort);
		String[] params = parseListParams(rawMessage);
		for (String param : params) {
		    // [riderID.rideID.version,riderTCPAddress,riderTCPport,destination,places,time]
		    String[] fields = parseParams(param);

		    String[] fullRideID = fields[0].split(RIDE_ID_SEPARATOR);
		    String peerID = fullRideID[0];
		    String rideID = fullRideID[1];
		    int version = Integer.parseInt(fullRideID[2]);

		    String address = fields[1];
		    int port = Integer.parseInt(fields[2]);
		    String destination = fields[3];
		    int places = Integer.parseInt(fields[4]);
		    Date time = new Date(Long.parseLong(fields[5]));

		    msg.addRide(destination, rideID, peerID, address, port, places, time, version);
		}
		return msg;
	    } catch (ArrayIndexOutOfBoundsException e) {
		e.printStackTrace();
		throw new InvalidMessageException();
	    }
	}

	private static String parseSenderIP(String rawMessage) {
	    String[] tokens = rawMessage.trim().split(SEPARATOR);
	    return tokens[2];
	}

	private static int parseSenderPort(String rawMessage) {
	    String[] tokens = rawMessage.trim().split(SEPARATOR);
	    return Integer.valueOf(tokens[3]);
	}

	private static String[] parseListParams(String rawMessage) {
	    try {
		String[] tokens = rawMessage.trim().split(SEPARATOR);
		String[] params = tokens[4].split(LIST_SEPARATOR);
		return params;
	    } catch (ArrayIndexOutOfBoundsException e) {
		return new String[0];
	    }
	}

    }

}
